﻿
function mergeUint8Arrays(arrs) {
    let cap = 0;
    for (let arr of arrs)
        cap += arr.length;
    let dstArr = new Uint8Array(cap);
    let offset = 0;
    for (let arr of arrs) {
        dstArr.set(arr, offset);
        offset += arr.length;
    }
    return dstArr;
}

export async function renderPixels(domCanvasId, compressedRgbaArray, rgbaLen) {
    //console.log('renderPixels.debugA');
    let domCanvas=document.getElementById(domCanvasId);
    if (domCanvas == null)
        return;
    //console.log(rgbaLen);
    let canvasContext = domCanvas.getContext("2d");
    //console.log(canvasContext);

    //console.log(domCanvas.width + ", " + domCanvas.height);
    if (domCanvas.width == 0 || domCanvas.height == 0)
        return;

    let imageData = canvasContext.createImageData(domCanvas.width, domCanvas.height);
    if (imageData.data.length == rgbaLen) {
        //console.log('renderPixels.debugB');
        //console.log('renderPixels.debugB',compressedRgbaArray);
        //console.log(new Blob([compressedRgbaArray]).size);

        const ds = new DecompressionStream("gzip");
        const decompressedStream = new Blob([compressedRgbaArray]).stream().pipeThrough(ds);
        //console.log(new Response(decompressedStream).arrayBuffer.length);
        //console.log(decompressedStream.getReader());

        let arrs = [];
        let reader = decompressedStream.getReader();
        while (true) {
            const { done, value } = await reader.read();
            if (done)
                break;
            arrs.push(value);
        }

        let dstArr = mergeUint8Arrays(arrs);
        //console.log(Buffer.concate(arr));
        //console.log(dstArr);
        //console.log(rgba);
        //console.log(arr);
        imageData?.data.set(dstArr);
        canvasContext?.putImageData(imageData, 0, 0); // at coords 0,0
    }
    //console.log('renderPixels.debugC');
}

export function getCanvasSize(domCanvasId) {
    let domCanvas = document.getElementById(domCanvasId);
    if (domCanvas && domCanvas.width && domCanvas.height)
        return { w: domCanvas.width, h: domCanvas.height };
    else
        return { w: 0, h: 0 };
}

let localRegCallbackResult = null;
export function regCallback(csThis, domCanvasId) {
    let domCanvas = document.getElementById(domCanvasId);
    //console.log("domCanvas:" + domCanvas);
    if (domCanvas == null)
        return;
    let funcResize = function (entries) {
        //console.log(entries[0]);
        for (let entry of entries) {
            const cr = entry.contentRect;
            const w = parseInt(cr.width, 10);
            const h = parseInt(cr.height, 10);

            //note that html canvas width height is different than the css width and height.
            //html canvas width and height is used for 'putImageData' pixel rendering.
            //if not set, the default value is 300 & 150.
            //quote: "he canvas element has two attributes to control the size of the element's bitmap: width and height.".
            domCanvas.width = w;
            domCanvas.height = h;

            //console.log("funcResize", cr.width + ", " + cr.height);
            //console.log(entry);
            //console.log(cr.width + ", " + cr.height);
            //console.log(w + ", " + h);
            //console.log(domCanvas.width + ", " + domCanvas.height);

            //console.log("funcResize");
            try {
                csThis.invokeMethodAsync('Resize', w, h);
            }
            catch (e){
                console.error(e);
            }
        }
    };
    let resizeObserver = new ResizeObserver(funcResize);
    resizeObserver.observe(domCanvas);

    let funcVisibleChanged = function () {
        //console.log("VisibleChanged", domCanvas, domCanvas.csThis);
        csThis.invokeMethodAsync('VisibleChanged', document.visibilityState);
    }
    document.addEventListener('visibilitychange', funcVisibleChanged);

    //set passive false to avoid chrome scroll bar invocation.
    let funcMouseWheelXyz = function (e) {
        e.preventDefault();
        //console.log("funcMouseWheelXyz",csThis);
        csThis.invokeMethodAsync('MouseWheelXyz', e.deltaX, e.deltaY, e.deltaZ);
    };
    
    // Detect which wheel event to use
    let wheelEvent = 'onwheel' in domCanvas ? 'wheel' : 'mousewheel';
    domCanvas.addEventListener(wheelEvent, funcMouseWheelXyz, { passive: false });

    localRegCallbackResult = {
        resizeObserver: resizeObserver,
        funcVisibleChanged: funcVisibleChanged,
        funcMouseWheelXyz: funcMouseWheelXyz,
        wheelEvent: wheelEvent  // Store which event was used for cleanup
    };
}
export function dispose(domCanvasId) {
    if (localRegCallbackResult) {
        let domCanvas = document.getElementById(domCanvasId);
        localRegCallbackResult.resizeObserver.disconnect();
        document.removeEventListener('visibilitychange', localRegCallbackResult.funcVisibleChanged);
        if (domCanvas && localRegCallbackResult.wheelEvent) {
            domCanvas.removeEventListener(localRegCallbackResult.wheelEvent, localRegCallbackResult.funcMouseWheelXyz);
        }
        localRegCallbackResult = null;
    }
}

export function _focus(domCanvasId) {
    let domCanvas = document.getElementById(domCanvasId);
    domCanvas?.focus();
}
export function _setPointerCapture(domCanvasId, pointerId) {
    let domCanvas = document.getElementById(domCanvasId);
    //console.log("_SetPointerCapture");
    //console.log(pointerId);
    try {
        domCanvas?.setPointerCapture(pointerId);
    }
    catch (err) {
        if (JSON.stringify(err).indexOf("No active pointer with the given id is found.") != -1)
            console.log("Known Error by unmatured external system. pointer lost: " + pointerId);
    //    else
    //        throw err;
    }
}
export function _releasePointerCapture(domCanvasId, pointerId) {
    let domCanvas = document.getElementById(domCanvasId);
    //console.log("_ReleasePointerCapture");
    //console.log(pointerId);
    if (domCanvas?.hasPointerCapture(pointerId))
        domCanvas?.releasePointerCapture(pointerId);
}